package com.dungeon.game;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.ToggleButton;

import com.dungeon.game.Constants.Action_color_code;
import com.dungeon.game.Constants.Character_action_code;
import com.dungeon.game.Constants.Class_code;
import com.dungeon.game.Constants.Equipment_type_code;
import com.dungeon.game.Constants.Position_code;
import com.dungeon.game.Constants.Potion_type;
import com.dungeon.game.Constants.Scenario_code;

public class LaunchActivity extends Activity {

	static TextView tv;

	static AlertDialog dlg;

	static SoundPool spool;
	static HashMap<String,Integer> sound_list;
    static AudioManager audioManager;
    static Button myDifficultyButton;

    static String[] soundFileNames, imageFileNames;
    static GameImages gi;
    static AssetManager assetManager;

    boolean warned;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_launch);
	    myDifficultyButton = (Button)findViewById(R.id.DifficultyButton);
		warned = false;
		boolean loaded = false;
		String[] filenames = getFilesDir().list();
		Arrays.sort(filenames,Collections.reverseOrder());
		for (String file : filenames){
			Log.e("Demo","Trying " + file);
			if (file.substring(file.lastIndexOf('.') + 1).equals("sav") && Campaignstate.load(this,file)){ // or .save
				Log.e("Demo","OK");
				loaded = true;
				break;
			}
		}
		if (!loaded)
			Campaignstate.init();

        if (Campaignstate.difficulty_level==1){
        	myDifficultyButton.setText("Normal");
			myDifficultyButton.setTextColor(0xFF00BB00);
        }
        if (Campaignstate.difficulty_level==2){
        	myDifficultyButton.setText("Hard");
			myDifficultyButton.setTextColor(0xFFCC4400);
		}
        if (Campaignstate.difficulty_level==3){
        	myDifficultyButton.setText("Nightmare");
			myDifficultyButton.setTextColor(0xFFFF0000);
		}
        myDifficultyButton.invalidate();

		tv = (TextView)findViewById(R.id.textView2);
    	tv.setText("Your gold: " + Campaignstate.gold);
    	tv.invalidate();

    	assetManager = getAssets();

    	spool = new SoundPool(3,AudioManager.STREAM_MUSIC,0);
    	this.setVolumeControlStream(AudioManager.STREAM_MUSIC);

    	sound_list = new HashMap<String,Integer>();
		try {
			soundFileNames = assetManager.list("sounds");
	    } catch (IOException e) {
	    	finish();
		}
		sound_list.put("cancel",loadSoundFromAsset("sounds/cancel.wav"));

	    audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);

	    gi = new GameImages();
	    gi.init(this);
		try {
			imageFileNames = assetManager.list("images");
			gi.add("test_splash");
			gi.add("skull_crossbones");
			gi.add("fire");
			gi.add("cold");
			gi.add("lightning");
			gi.add("missile");
			gi.add("shadowbolt");
	    } catch (IOException e) {
	    	finish();
		}
	    Bitmap b = GameImages.image_list.get("skull_crossbones").i.get(GameImage.image_types.IT_BASIC);
	    Bitmap b2 = Bitmap.createBitmap(b.getWidth(),b.getHeight(),Bitmap.Config.ARGB_8888);
	    for(int x = 0; x < b.getWidth(); x++){
	        for(int y = 0; y < b.getHeight(); y++){
	        	int col = b.getPixel(x, y);
	            if (col == Color.BLACK)
	                b2.setPixel(x,y,Color.TRANSPARENT);
	            else
	            	b2.setPixel(x,y,col);
	        }
	    }
	    GameImages.image_list.get("skull_crossbones").i.put(GameImage.image_types.IT_BASIC, b2);
	    GameImages.image_list.put("fire_down", new GameImage());
	    GameImages.image_list.get("fire_down").i.put(GameImage.image_types.IT_BASIC, RotateBitmap(GameImages.image_list.get("fire").i.get(GameImage.image_types.IT_BASIC),180));
	    GameImages.image_list.put("cold_down", new GameImage());
	    GameImages.image_list.get("cold_down").i.put(GameImage.image_types.IT_BASIC, RotateBitmap(GameImages.image_list.get("cold").i.get(GameImage.image_types.IT_BASIC),180));
	    GameImages.image_list.put("lightning_down", new GameImage());
	    GameImages.image_list.get("lightning_down").i.put(GameImage.image_types.IT_BASIC, RotateBitmap(GameImages.image_list.get("lightning").i.get(GameImage.image_types.IT_BASIC),180));
	    GameImages.image_list.put("missile_down", new GameImage());
	    GameImages.image_list.get("missile_down").i.put(GameImage.image_types.IT_BASIC, RotateBitmap(GameImages.image_list.get("missile").i.get(GameImage.image_types.IT_BASIC),180));
	    GameImages.image_list.put("shadowbolt_down", new GameImage());
	    GameImages.image_list.get("shadowbolt_down").i.put(GameImage.image_types.IT_BASIC, RotateBitmap(GameImages.image_list.get("shadowbolt").i.get(GameImage.image_types.IT_BASIC),180));
	}

	public static Bitmap RotateBitmap(Bitmap source, float angle){
	      Matrix matrix = new Matrix();
	      matrix.postRotate(angle);
	      return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
	}

	public void onDifficultyButton(View v){
		if (Campaignstate.difficulty_level==1){
			Campaignstate.difficulty_level=2;
			myDifficultyButton.setText("Hard");
			myDifficultyButton.setTextColor(0xFFCC4400);
		} else if (Campaignstate.difficulty_level==2){
			Campaignstate.difficulty_level=3;
			myDifficultyButton.setText("Nightmare");
			myDifficultyButton.setTextColor(0xFFFF0000);
		} else if (Campaignstate.difficulty_level==3){
			Campaignstate.difficulty_level=1;
			myDifficultyButton.setText("Normal");
			myDifficultyButton.setTextColor(0xFF00bb00);
		}
		myDifficultyButton.invalidate();
	}

	public void onDumpButton(View v){
		if (Campaignstate.chars.size()<=6){
			notify(this, null, "Party is too small", "You cannot do without any of your remaining adventurers.");
		} else {
	        AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this);
	        ScrollView sv = new ScrollView(LaunchActivity.this);
	        sv.setBackgroundColor(Color.argb(0,0,0,0));
	        sv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
	        LinearLayout ll = new LinearLayout(LaunchActivity.this);
	        ll.setBackgroundColor(Color.argb(0,0,0,0));
	        ll.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
	        ll.setOrientation(LinearLayout.VERTICAL);
	        ll.setGravity(Gravity.TOP);
			int count=0;
			ArrayList<Unchoosable_charsheet_button> ds = new ArrayList<Unchoosable_charsheet_button>();
	        for (int i=0; i<Campaignstate.chars.size(); i++){
				LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,112);
				lp.setMargins(10, 7, 10, 7);
				Unchoosable_charsheet_button this_d = new Unchoosable_charsheet_button(LaunchActivity.this,Campaignstate.chars.get(i),i);
				ll.addView(this_d,lp);
				ds.add(this_d);
	        }
	        sv.addView(ll);
	        builder.setTitle("Retire a character")
	        .setCancelable(true)
	        .setView(sv)
	        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
	        	public void onClick(DialogInterface dialog, int id) {
	        		dialog.cancel();
	        		}});
	        dlg = builder.create();
	        for (int i=0; i<ds.size(); i++){
	        	Unchoosable_charsheet_button this_d = ds.get(i);
	        	this_d.setOnClickListener(new MyDListener(dlg,Campaignstate.chars.get(i)));
	        }
	        dlg.show();
		}
	}

    class MyDListener implements View.OnClickListener {
    	DialogInterface dlg;
    	Charsheet cs;

    	public MyDListener(DialogInterface _dlg, Charsheet _cs){
    		cs = _cs;
    		dlg = _dlg;
    	}

		public void onClick(View view) {
			if (cs.level > 5){
				LaunchActivity.notify(LaunchActivity.this, cs.image, "Character is too experienced", cs.name + " has been with you for a long time and will not leave you now.");
				playSound("cancel");
			} else {
				LaunchActivity.notify(LaunchActivity.this, cs.image, "Character has retired", cs.name + " sadly waves goodbye.");
				if (cs.armor!=null) Campaignstate.items_owned.add(cs.armor);
				if (cs.offhand!=null) Campaignstate.items_owned.add(cs.offhand);
				if (cs.melee_weapon!=null) Campaignstate.items_owned.add(cs.melee_weapon);
				if (cs.missile_weapon!=null) Campaignstate.items_owned.add(cs.missile_weapon);
				for (Item i : cs.trinkets) Campaignstate.items_owned.add(i);
				int number = -1;
				for (int j=0; j<Campaignstate.chars.size(); j++){
					if (Campaignstate.chars.get(j).equals(cs)){
						number = j;
					}
				}
				Campaignstate.chars.remove(cs);
				for (int j=0; j<Campaignstate.current_party.size(); j++){
					if (Campaignstate.current_party.get(j)==number)
						Campaignstate.current_party.remove(j);
				}
				for (int j=0; j<Campaignstate.current_party.size(); j++){
					if (Campaignstate.current_party.get(j)>number)
						Campaignstate.current_party.set(j, Campaignstate.current_party.get(j) - 1);
				}
			}
			dlg.dismiss();
	    }
    }

	public void onRecruitButton(View v){
		if (Campaignstate.available_recruits.size()==0){
			notify(this, null, "No recruits", "There are no likely-looking adventurers at the inn today.");
		} else {
	        AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this);
	        ScrollView sv = new ScrollView(LaunchActivity.this);
	        sv.setBackgroundColor(Color.argb(0,0,0,0));
	        sv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
	        LinearLayout ll = new LinearLayout(LaunchActivity.this);
	        ll.setBackgroundColor(Color.argb(0,0,0,0));
	        ll.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
	        ll.setOrientation(LinearLayout.VERTICAL);
	        ll.setGravity(Gravity.TOP);
			int count=0;
			ArrayList<Recruit_button> bs = new ArrayList<Recruit_button>();
			ArrayList<Recruit> rs = new ArrayList<Recruit>();
	        for (Recruit r : Campaignstate.available_recruits){
				if (r.current_gold_cost() <= Campaignstate.gold){
					LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,112);
					lp.setMargins(10, 7, 10, 7);
					Recruit_button this_b = new Recruit_button(LaunchActivity.this,r);
					ll.addView(this_b,lp);
					bs.add(this_b);
					rs.add(r);
				}
	        }
	        if (rs.size()==0){
				notify(this, null, "No recruits", "There are no likely-looking adventurers at the inn today.");
				return;
	        }
	        sv.addView(ll);
	        builder.setTitle("Recruit a character")
	        .setCancelable(true)
	        .setView(sv)
	        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
	        	public void onClick(DialogInterface dialog, int id) {
	        		dialog.cancel();}});
	        dlg = builder.create();
	        for (int i=0; i<bs.size(); i++){
	        	Recruit_button this_b = bs.get(i);
	        	this_b.setOnClickListener(new MyRListener(dlg,rs.get(i)));
	        }
	        dlg.show();
		}
	}

    class MyRListener implements View.OnClickListener {
    	DialogInterface dlg;
    	Recruit r;
    	WrapInt stat1, stat2, constitution, stamina, training, reflexes;

    	public MyRListener(DialogInterface _dlg, Recruit _r){
    		r = _r;
    		dlg = _dlg;
    	}

		public void onClick(View view) {
			dlg.dismiss();
			stat1 = new WrapInt(1);
			stat2 = new WrapInt(1);
			constitution = new WrapInt(1);
			stamina = new WrapInt(1);
			training = new WrapInt(1);
			reflexes = new WrapInt(1);
			int min_stat1=1, min_stat2=1, min_constitution=1, min_stamina=1, min_training=1, min_reflexes=1;
			if (r.fixed_stat.equals("power") || r.fixed_stat.equals("strength") || r.fixed_stat.equals("valor") || r.fixed_stat.equals("daring")){
				stat1.value = r.fixed_stat_value;
				min_stat1 = r.fixed_stat_value;
			}
			if (r.fixed_stat.equals("subtlety") || r.fixed_stat.equals("skill") || r.fixed_stat.equals("wisdom") || r.fixed_stat.equals("cunning")){
				stat2.value = r.fixed_stat_value;
				min_stat2 = r.fixed_stat_value;
			}
			if (r.fixed_stat.equals("constitution")){
				constitution.value = r.fixed_stat_value;
				min_constitution = r.fixed_stat_value;
			}
			if (r.fixed_stat.equals("stamina")){
				stamina.value = r.fixed_stat_value;
				min_stamina = r.fixed_stat_value;
			}
			if (r.fixed_stat.equals("training")){
				training.value = r.fixed_stat_value;
				min_training = r.fixed_stat_value;
			}
			if (r.fixed_stat.equals("reflexes")){
				reflexes.value = r.fixed_stat_value;
				min_reflexes = r.fixed_stat_value;
			}
			WrapInt remaining_points = new WrapInt(r.points-training.value-constitution.value-stamina.value-reflexes.value-stat1.value-stat2.value);
			View dlgView = View.inflate(LaunchActivity.this, R.layout.dialog_new_recruit, null);
			TextView stat1_name = (TextView)dlgView.findViewById(R.id.stat1_name);
			TextView stat2_name = (TextView)dlgView.findViewById(R.id.stat2_name);
			TextView stat3_name = (TextView)dlgView.findViewById(R.id.stat3_name);
			TextView stat4_name = (TextView)dlgView.findViewById(R.id.stat4_name);
			TextView stat5_name = (TextView)dlgView.findViewById(R.id.stat5_name);
			TextView stat6_name = (TextView)dlgView.findViewById(R.id.stat6_name);
			TextView stat1_value = (TextView)dlgView.findViewById(R.id.stat1_value);
			TextView stat2_value = (TextView)dlgView.findViewById(R.id.stat2_value);
			TextView stat3_value = (TextView)dlgView.findViewById(R.id.stat3_value);
			TextView stat4_value = (TextView)dlgView.findViewById(R.id.stat4_value);
			TextView stat5_value = (TextView)dlgView.findViewById(R.id.stat5_value);
			TextView stat6_value = (TextView)dlgView.findViewById(R.id.stat6_value);
			if (r.class_code==Class_code.C_MAGE){
				stat1_name.setText("Power: ");
				stat2_name.setText("Subtlety: ");
			} else if (r.class_code==Class_code.C_PRIEST){
				stat1_name.setText("Valor: ");
				stat2_name.setText("Wisdom: ");
			} else if (r.class_code==Class_code.C_ROGUE){
				stat1_name.setText("Daring: ");
				stat2_name.setText("Cunning: ");
			} else if (r.class_code==Class_code.C_WARRIOR){
				stat1_name.setText("Strength: ");
				stat2_name.setText("Skill: ");
			}
			stat1_value.setText(stat1.value+" ");
			stat2_value.setText(stat2.value+" ");
			stat3_name.setText("Constitution: ");
			stat3_value.setText(constitution.value+" ");
			stat4_name.setText("Energy: ");
			stat4_value.setText(stamina.value+" ");
			stat5_name.setText("Training: ");
			stat5_value.setText(training.value+" ");
			stat6_name.setText("Reflexes: ");
			stat6_value.setText(reflexes.value+" ");
			Button stat1_minus = (Button)dlgView.findViewById(R.id.stat1_minus);
			Button stat2_minus = (Button)dlgView.findViewById(R.id.stat2_minus);
			Button stat3_minus = (Button)dlgView.findViewById(R.id.stat3_minus);
			Button stat4_minus = (Button)dlgView.findViewById(R.id.stat4_minus);
			Button stat5_minus = (Button)dlgView.findViewById(R.id.stat5_minus);
			Button stat6_minus = (Button)dlgView.findViewById(R.id.stat6_minus);
			Button stat1_plus = (Button)dlgView.findViewById(R.id.stat1_plus);
			Button stat2_plus = (Button)dlgView.findViewById(R.id.stat2_plus);
			Button stat3_plus = (Button)dlgView.findViewById(R.id.stat3_plus);
			Button stat4_plus = (Button)dlgView.findViewById(R.id.stat4_plus);
			Button stat5_plus = (Button)dlgView.findViewById(R.id.stat5_plus);
			Button stat6_plus = (Button)dlgView.findViewById(R.id.stat6_plus);
			BitmapDrawable question = new BitmapDrawable(getResources(),gi.getImageBasic("question"));
			ImageButton info1 = (ImageButton)dlgView.findViewById(R.id.info1);
			ImageButton info2 = (ImageButton)dlgView.findViewById(R.id.info2);
			ImageButton info3 = (ImageButton)dlgView.findViewById(R.id.info3);
			ImageButton info4 = (ImageButton)dlgView.findViewById(R.id.info4);
			ImageButton info5 = (ImageButton)dlgView.findViewById(R.id.info5);
			ImageButton info6 = (ImageButton)dlgView.findViewById(R.id.info6);
			info1.setBackgroundDrawable(question);
			info2.setBackgroundDrawable(question);
			info3.setBackgroundDrawable(question);
			info4.setBackgroundDrawable(question);
			info5.setBackgroundDrawable(question);
			info6.setBackgroundDrawable(question);
			TextView remaining = (TextView)dlgView.findViewById(R.id.remaining_points);
			remaining.setText(remaining_points.value + " points remaining");
			stat1_minus.setOnClickListener(new MinusListener(stat1,min_stat1,stat1_value,remaining_points,remaining));
			stat2_minus.setOnClickListener(new MinusListener(stat2,min_stat2,stat2_value,remaining_points,remaining));
			stat3_minus.setOnClickListener(new MinusListener(constitution,min_constitution,stat3_value,remaining_points,remaining));
			stat4_minus.setOnClickListener(new MinusListener(stamina,min_stamina,stat4_value,remaining_points,remaining));
			stat5_minus.setOnClickListener(new MinusListener(training,min_training,stat5_value,remaining_points,remaining));
			stat6_minus.setOnClickListener(new MinusListener(reflexes,min_reflexes,stat6_value,remaining_points,remaining));
			stat1_plus.setOnClickListener(new PlusListener(stat1,stat1_value,remaining_points,remaining));
			stat2_plus.setOnClickListener(new PlusListener(stat2,stat2_value,remaining_points,remaining));
			stat3_plus.setOnClickListener(new PlusListener(constitution,stat3_value,remaining_points,remaining));
			stat4_plus.setOnClickListener(new PlusListener(stamina,stat4_value,remaining_points,remaining));
			stat5_plus.setOnClickListener(new PlusListener(training,stat5_value,remaining_points,remaining));
			stat6_plus.setOnClickListener(new PlusListener(reflexes,stat6_value,remaining_points,remaining));
			if (r.class_code==Class_code.C_MAGE){
				info1.setOnClickListener(new OnClickListener(){	public void onClick(View v) {LaunchActivity.notify(LaunchActivity.this, null, "Power","A high Power makes you do more damage with wands and attack spells.");}});
				info2.setOnClickListener(new OnClickListener(){	public void onClick(View v) {LaunchActivity.notify(LaunchActivity.this, null, "Subtlety","A high Subtlety makes you more likely to hit with wands, and unlocks or boosts many non-combat spells, such as Confusion or Cloak of Shadows.");}});
			} else if (r.class_code==Class_code.C_ROGUE){
				info1.setOnClickListener(new OnClickListener(){	public void onClick(View v) {LaunchActivity.notify(LaunchActivity.this, null, "Daring","A high Daring increases your evasion, and makes you attack more often and more accurately at both close and long range, as well as unlocking some abilities like Dodge.");}});
				info2.setOnClickListener(new OnClickListener(){	public void onClick(View v) {LaunchActivity.notify(LaunchActivity.this, null, "Cunning","A high Cunning unlocks or boosts many non-combat abilities, such as Move Silently or Find Traps.");}});
			} else if (r.class_code==Class_code.C_WARRIOR){
				info1.setOnClickListener(new OnClickListener(){	public void onClick(View v) {LaunchActivity.notify(LaunchActivity.this, null, "Strength","A high Strength increases your melee damage, as well as unlocking some abilities like Knockback.");}});
				info2.setOnClickListener(new OnClickListener(){	public void onClick(View v) {LaunchActivity.notify(LaunchActivity.this, null, "Skill","A high Skill increases your evasion, and makes you attack more often and more accurately in melee, as well as unlocking some abilities like Deflect.");}});
			} else if (r.class_code==Class_code.C_PRIEST){
				info1.setOnClickListener(new OnClickListener(){	public void onClick(View v) {LaunchActivity.notify(LaunchActivity.this, null, "Valor","A high Valor increases your melee damage, as well as unlocking some abilities like Exhort.");}});
				info2.setOnClickListener(new OnClickListener(){	public void onClick(View v) {LaunchActivity.notify(LaunchActivity.this, null, "Wisdom","A high Wisdom makes your healing spells more effective, as well as unlocking some abilities like Cure Poison.");}});
			}
			info3.setOnClickListener(new OnClickListener(){	public void onClick(View v) {LaunchActivity.notify(LaunchActivity.this, null, "Constitution", "A high Constitution gives you more health, and also unlocks a few abilities like Resist Fear.");}});
			info4.setOnClickListener(new OnClickListener(){	public void onClick(View v) {LaunchActivity.notify(LaunchActivity.this, null, "Energy", "A high Energy makes your abilities cost less energy bar.");}});
			info5.setOnClickListener(new OnClickListener(){	public void onClick(View v) {LaunchActivity.notify(LaunchActivity.this, null, "Training", "A high Training allows you to learn more abilities.");}});
			info6.setOnClickListener(new OnClickListener(){	public void onClick(View v) {LaunchActivity.notify(LaunchActivity.this, null, "Reflexes", "Characters with high Reflexes will sometimes use their abilities at appropriate times, even if you don't ask them to.");}});
			AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this);
			builder.setIcon(new BitmapDrawable(getResources(),gi.getImageBasic(r.image)));
			builder.setTitle(r.name);
			builder.setView(dlgView)
			.setPositiveButton("OK", new FinishRecruitListener(this))
			.show();
	    }
    }

    class FinishRecruitListener implements DialogInterface.OnClickListener{
    	MyRListener parent;

    	public FinishRecruitListener(MyRListener _parent){
    		parent = _parent;
    	}

	    public void onClick(DialogInterface dialog, int id) {
	    	if (parent.training.value+parent.stat1.value+parent.stat2.value+parent.constitution.value+parent.stamina.value+parent.reflexes.value == parent.r.points){
				Campaignstate.chars.add(new Charsheet(parent.r.class_code,parent.r.image,parent.r.name,parent.r.level,
						parent.training.value,parent.stat1.value,parent.stat2.value,parent.constitution.value,parent.stamina.value,parent.reflexes.value,
						new ArrayList<Character_action_code>(),new ArrayList<Character_action_code>(),new ArrayList<Potion_type>(),
						null,null,null,null,null,null,null,parent.r.genesis));
				if (Campaignstate.current_party.size()<6)
					Campaignstate.current_party.add(Campaignstate.chars.size()-1);
				Campaignstate.gold = Campaignstate.gold - parent.r.current_gold_cost();
				Campaignstate.available_recruits.remove(parent.r);
		    	tv.setText("Your gold: " + Campaignstate.gold);
		    	tv.invalidate();
	    	} else {
	    		LaunchActivity.notify(LaunchActivity.this,null,"Some points unspent","You have not spent all this recruit's attribute points - try again.");
	    		playSound("cancel");
	    	}
	    }
    }

    class MinusListener implements OnClickListener{

    	WrapInt stat, remaining_points;
    	int min;
    	TextView value, remaining;

    	public MinusListener(WrapInt _stat,int _min,TextView _value,WrapInt _remaining_points,TextView _remaining){
    		stat = _stat;
    		remaining_points = _remaining_points;
    		min = _min;
    		value = _value;
    		remaining = _remaining;
    	}

		public void onClick(View v) {
			if (stat.value>min){
				remaining_points.value = remaining_points.value+1;
				stat.value = stat.value-1;
				value.setText(stat.value+" ");
				remaining.setText(remaining_points.value + " points remaining");
				value.invalidate();
				remaining.invalidate();
			}
		}
    }

    class PlusListener implements OnClickListener{

    	WrapInt stat, remaining_points;
    	TextView value, remaining;

    	public PlusListener(WrapInt _stat,TextView _value,WrapInt _remaining_points,TextView _remaining){
    		stat = _stat;
    		remaining_points = _remaining_points;
    		value = _value;
    		remaining = _remaining;
    	}

		public void onClick(View v) {
			if (stat.value<7 && remaining_points.value>0){
				remaining_points.value = remaining_points.value-1;
				stat.value = stat.value+1;
				value.setText(stat.value+" ");
				remaining.setText(remaining_points.value + " points remaining");
				value.invalidate();
				remaining.invalidate();
			}
		}
    }

    public void onGoButton(View v){
    	Campaignstate.mission_chosen = null;
        AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this);
        ScrollView sv = new ScrollView(LaunchActivity.this);
        sv.setBackgroundColor(Color.argb(0,0,0,0));
        sv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
        LinearLayout ll = new LinearLayout(LaunchActivity.this);
        ll.setBackgroundColor(Color.argb(0,0,0,0));
        ll.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
        ll.setOrientation(LinearLayout.VERTICAL);
        ll.setGravity(Gravity.TOP);
		int count=0;
		ArrayList<Button> sbs = new ArrayList<Button>();
		ArrayList<Scenario_code> scs = new ArrayList<Scenario_code>();
		for (Scenario_code s : Scenario_code.values()){
			if ((s!=Scenario_code.SC_ALEX) && (s.get_prerequisite() == null || Campaignstate.victories.contains(s.get_prerequisite()))){
				scs.add(s);
	        	LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,50);
	            lp.setMargins(10, 7, 10, 7);
	            int button_color = Color.WHITE;
	            if (!Campaignstate.victories.contains(s)) button_color = Action_color_code.ACC_RED.get_color();
	            Button sb = new ColorButton(LaunchActivity.this,button_color);
	            sb.setText(s.get_name());
	            sbs.add(sb);
	        	ll.addView(sb,lp);
	        	sb.invalidate();
	        	count = count + 1;
			}
		}
        sv.addView(ll);
        builder.setTitle("Choose a mission")
        .setCancelable(true)
        .setView(sv)
        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        	public void onClick(DialogInterface dialog, int id) {
        		dialog.cancel();}});
        AlertDialog mdlg = builder.create();
        for (int i=0; i<sbs.size(); i++){
        	Button sb = sbs.get(i);
        	sb.setOnClickListener(new MyBListener(mdlg,scs.get(i)));
        }
        mdlg.show();
    }

    class ColorButton extends Button {
    	public ColorButton(Context ct, int c){
    		super(ct);
    		getBackground().setColorFilter(c,PorterDuff.Mode.SRC_ATOP);
    	}
    }

    Scenario_code sc_chosen;

    class MyBListener implements View.OnClickListener {
    	DialogInterface dlg;
    	Scenario_code sc;

    	public MyBListener(DialogInterface _dlg, Constants.Scenario_code _sc){
    		sc = _sc;
    		dlg = _dlg;
    	}

		public void onClick(View view) {
			boolean ok = true;
			for (int i : Campaignstate.current_party){
				if (Campaignstate.chars.get(i).level > sc.get_max_level())
					ok = false;
			}
			if (ok){
				ArrayList<Charsheet> need_training = new ArrayList<Charsheet>();
				ArrayList<Charsheet> need_equipment = new ArrayList<Charsheet>();
				for (int i : Campaignstate.current_party){
					Charsheet this_char = Campaignstate.chars.get(i);
					if (!warned){
						if (this_char.master_action_codes.size() + this_char.obsoleted_actions.size() < this_char.get_n_skills())
							need_training.add(this_char);
						if ((this_char.melee_weapon==null && this_char.missile_weapon==null))
							need_equipment.add(this_char);
					}
				}
				if (need_training.size()>1){
					String character_names = need_training.get(0).name;
					for (int i=1; i<need_training.size(); i++){
						character_names = character_names + " and " + need_training.get(1).name;
					}
					LaunchActivity.notify(LaunchActivity.this, null, "Characters need training", character_names + " need more training. You can do this by going back to town, clicking on the 'Your home' button, clicking on the blue question mark next to the character, scrolling down to their abilities, and clicking the 'Learn another action' button.");
				} else if (need_training.size()==1){
					LaunchActivity.notify(LaunchActivity.this, null, "Characters need training", need_training.get(0).name + " needs more training. You can do this by going back to town, clicking on the 'Your home' button, clicking on the blue question mark next to the character, scrolling down to their abilities, and clicking the 'Learn another action' button.");
				} else {
					if (need_equipment.size()>1){
						String character_names = need_equipment.get(0).name;
						for (int i=1; i<need_training.size(); i++){
							character_names = character_names + " and " + need_equipment.get(1).name;
						}
						LaunchActivity.notify(LaunchActivity.this, null, "Characters need equipment", character_names + " are poorly equipped. When you have money, you can fix this by going back to town, clicking on the 'Your home' button, clicking on the blue question mark next to the character, scrolling down to their equipment, and clicking the 'Buy' button.");
					} else if (need_equipment.size()==1){
						LaunchActivity.notify(LaunchActivity.this, null, "Characters need equipment", need_equipment.get(0).name + " is poorly equipped. When you have money, you can fix this by going back to town, clicking on the 'Your home' button, clicking on the blue question mark next to the character, scrolling down to their equipment, and clicking the 'Buy' button.");
					}
					if (Campaignstate.gold < 10*need_equipment.size()){
						Campaignstate.gold = 10*need_equipment.size();
			       		tv.setText("Your gold: " + Campaignstate.gold);
			       		tv.invalidate();
					}
				}
				if (!(need_training.size()>0 || need_equipment.size()>0)){
					warned = false;
					LaunchActivity.this.sc_chosen = sc;
					Campaignstate.mission_chosen = new Scenario(sc);
			        Intent myIntent = new Intent(LaunchActivity.this, MainActivity.class);
			        LaunchActivity.this.startActivityForResult(myIntent,12);
				} else {
					warned = true;
				}
			} else {
				LaunchActivity.notify(LaunchActivity.this, null, "Characters are too high level", "You cannot take characters above level " + sc.get_max_level() + " into this dungeon.");
				playSound("cancel");
			}
			dlg.dismiss();
	    }
    }

    public void onReviewPartyButton(View v){
    	if (Campaignstate.current_party.size()==0) return;
        AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this);
        ScrollView sv = new ScrollView(LaunchActivity.this);
        sv.setBackgroundColor(Color.argb(0,0,0,0));
        sv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
        LinearLayout ll = new LinearLayout(LaunchActivity.this);
        ll.setBackgroundColor(Color.argb(0,0,0,0));
        ll.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
        ll.setOrientation(LinearLayout.VERTICAL);
        ll.setGravity(Gravity.TOP);
        for (int i=0; i<Campaignstate.current_party.size(); i++){
        	LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,112);
            lp.setMargins(10, 7, 10, 7);
        	ll.addView(new Unchoosable_charsheet_button(LaunchActivity.this,Campaignstate.chars.get(Campaignstate.current_party.get(i)),Campaignstate.current_party.get(i)),lp);
        }
        sv.addView(ll);
        builder.setTitle("Review the party")
        .setCancelable(true)
        .setView(sv)
        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
        	public void onClick(DialogInterface dialog, int id) {
        		dialog.cancel();}});
        dlg = builder.create();
        dlg.setOnDismissListener(new OnDismissListener(){
       	public void onDismiss(DialogInterface dialog) {
       		tv.setText("Your gold: " + Campaignstate.gold);
       		tv.invalidate();}
          });
        dlg.show();
    }

    static AlertDialog id_shown;

    public void onStoreroomButton(View v){
    	if (Campaignstate.items_owned.size()==0){
    		notify(LaunchActivity.this,null,"Storeroom","The storeroom is empty.\n\n");
    		return;
    	}
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        ScrollView sv = new ScrollView(this);
        sv.setBackgroundColor(Color.argb(0,0,0,0));
        sv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
        LinearLayout lld = new LinearLayout(this);
        lld.setBackgroundColor(Color.BLACK);
        lld.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
        lld.setOrientation(LinearLayout.VERTICAL);
        lld.setGravity(Gravity.TOP);
    	HashMap<Item,Integer> item_frequencies = new HashMap<Item,Integer>();
        for (Item i : Campaignstate.items_owned){
        	boolean already = false;
        	for (Item i2 : item_frequencies.keySet()){
        		if (i.getClass().equals(i2.getClass())){
        			already = true;
        			item_frequencies.put(i2,item_frequencies.get(i2)+1);
        			break;
        		}
        	}
        	if (!already)
        		item_frequencies.put(i,1);
        }
        ArrayList<Item> keys = new ArrayList<Item>(item_frequencies.keySet());
        Collections.sort(keys,new Comparator<Item>(){public int compare(Item lhs, Item rhs){return rhs.cost().compareTo(lhs.cost());}});
        for (Item i : keys){
        	String name, description;
        	int n = item_frequencies.get(i);
        	if (n>1){
            	name = i.name() + " (" + n + ")";
        	} else {
            	name = i.name();
        	}
        	description = i.description();
        	UnchooseableChoiceButton sb = new UnchooseableChoiceButton(this,name,description,i.image);
			lld.addView(sb);
        }
        sv.addView(lld);
        builder.setTitle("Storeroom")
        .setCancelable(true)
        .setView(sv)
        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
        	public void onClick(DialogInterface dialog, int id) {
        		dialog.cancel();}});
        id_shown = builder.create();
        id_shown.show();
    }

    class UnchooseableChoiceButton extends RelativeLayout {

    	public UnchooseableChoiceButton(Context context, String name, String description, String image) {
			super(context);
    		setBackgroundColor(Color.WHITE);
            LinearLayout.LayoutParams all = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            all.setMargins(1,2,2,1);
            setLayoutParams(all);
    	    ImageView item0 = new ImageView(context);
    	    int mid_width = 300;
    	    if (image!=null && image!=""){
                RelativeLayout.LayoutParams leftest = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        	    leftest.addRule(RelativeLayout.CENTER_VERTICAL);
        	    leftest.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
	    	    item0.setBackgroundDrawable(new BitmapDrawable(this.getResources(),gi.getImageBasic(image)));
	            addView(item0,leftest);
	    	    item0.setId(19999);
    	    } else {
    	    	mid_width = mid_width + 80;
    	    }
            RelativeLayout.LayoutParams left = new RelativeLayout.LayoutParams(mid_width, RelativeLayout.LayoutParams.WRAP_CONTENT);
    	    left.addRule(RelativeLayout.ALIGN_PARENT_TOP);
    	    if (image!=null && image!=""){
    	    	left.addRule(RelativeLayout.RIGHT_OF, item0.getId());
    	    } else {
    	    	left.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
    	    }
    	    TextView item1 = new TextView(context);
    	    item1.setText(name);
    	    item1.setTextColor(Color.BLACK);
    	    item1.setTypeface(item1.getTypeface(), Typeface.BOLD);
            addView(item1,left);
    	    item1.setId(20000);
    	    RelativeLayout.LayoutParams below = new RelativeLayout.LayoutParams(mid_width, RelativeLayout.LayoutParams.WRAP_CONTENT);
    	    if (image!=null && image!=""){
    	    	below.addRule(RelativeLayout.RIGHT_OF, item0.getId());
    	    } else {
    	    	below.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
    	    }
    	    below.addRule(RelativeLayout.BELOW, item1.getId());
    	    TextView item2 = new TextView(context);
    	    item2.setText(description);
    	    item2.setTextColor(Color.BLACK);
    	    item2.setWidth(310);
    	    addView(item2,below);
		}
    }

    public void onQuestListButton(View v){
    	String text="";
		int quests = 0;
		if (Campaignstate.victories.contains(Scenario_code.SC_DESERT)){
			if (Campaignstate.victories.contains(Scenario_code.SC_LICH)){
	    		text = text + "Rejoice - the evil is defeated!\n\n";
			} else {
	    		text = text + "A dark power has arisen in the ruins of an old fort, not far to the north. Defeat it before the forces of evil overrun this land!\n\n";
			}
			notify(this,"scroll","The noticeboard in the town square",text);
			return;
		}
		if (Campaignstate.victories.size()==0){
			notify(this,"scroll","The noticeboard in the town square","Go to the town gate to do the Tutorial...\n\n");
			return;
		} else if (Campaignstate.victories.contains(Scenario_code.SC_TUTORIAL) && Campaignstate.victories.size()==1){
			notify(this,"scroll","The noticeboard in the town square","Why don't you try the caves near town next...\n\n");
			return;
		} else if (Campaignstate.victories.contains(Scenario_code.SC_EASY) && !Campaignstate.victories.contains(Scenario_code.SC_RANDOM_3)){
			notify(this,"scroll","The noticeboard in the town square","Why don't you try the L3 random dungeon next... That will unlock a lot of other quests.\n\n");
			return;
		}
    	if (!Campaignstate.victories.contains(Scenario_code.SC_TROLL_1)){
    		text = text + "Warning: Don't cross the Trollsbridge or an impudent troll may seize your goods.\n\n";
    		quests = quests + 1;
    	}
    	if (!Campaignstate.victories.contains(Scenario_code.SC_CRYPT_1)){
    		text = text + "Reward for bringing back an impudent apprentice sorcerer - the truant will soon be copying out ten thousand lines!\n\n";
    		quests = quests + 1;
    	}
    	if (quests<2 && !Campaignstate.victories.contains(Scenario_code.SC_TROGLODYTE_2)){
    		text = text + "Does anyone know an efficacious remedy against Troglodytes? We have a nest of them on our property. Any advice appreciated.\n\n";
    		quests = quests + 1;
    	}
    	if (quests<3 && !Campaignstate.victories.contains(Scenario_code.SC_RED_DRAGON)){
    		text = text + "May some hero save us from the dragon that burns our crops, devours our stock and carries off our daughters, otherwise we are all utterly ruined and lost.\n\n";
    		quests = quests + 1;
    	}
		if (quests<2 && !Campaignstate.victories.contains(Scenario_code.SC_ORC_3) && Campaignstate.victories.contains(Scenario_code.SC_ORC_1)){
    		text = text + "HEAR YE, HEAR YE. All citizens of an age to bear arms must report to the barracks for training - orc scouts have crossed the border!\n\n";
    		quests = quests + 1;
    	}
    	if (quests<2 && !Campaignstate.victories.contains(Scenario_code.SC_CRAG) && Campaignstate.victories.contains(Scenario_code.SC_LABYRINTH)){
    		text = text + "For sale: Climbing gear. Good condition, somewhat used. Giving up the hobby - too dangerous!\n\n";
    		quests = quests + 1;
    	}
		if (quests<2 && !Campaignstate.victories.contains(Scenario_code.SC_FOREST_FIRE) && Campaignstate.victories.contains(Scenario_code.SC_ORC_1) && Campaignstate.one_in(2)){
    		text = text + "Volunteer fire fighters wanted.\n\n";
    		quests = quests + 1;
    	}
		if (quests<2 && !Campaignstate.victories.contains(Scenario_code.SC_DARK_TEMPLE_1) && Campaignstate.victories.contains(Scenario_code.SC_CRYPT_1) && Campaignstate.one_in(2)){
    		text = text + "Not sure where your life is taking you? Wondering about the reasons why we're all here? Join us at the Temple (of Evil). Heed the call to worship (Evil), join our congregation as we raise our hands in joyful praise (of Evil), and participate in our (Evil) liturgy!\n\n";
    		quests = quests + 1;
    	}
    	if (quests<2 && !Campaignstate.victories.contains(Scenario_code.SC_PYRAMID_1) && Campaignstate.victories.contains(Scenario_code.SC_CRYPT_1)){
    		text = text + "Sign here, he who has the courage to plumb the mysteries of the ancient Pyramid. An expedition will soon set off across the desert.\n\n";
    		quests = quests + 1;
    	}
    	if (quests<2 && !Campaignstate.victories.contains(Scenario_code.SC_WIZARD_TOWER_3) && Campaignstate.one_in(3)){
    		text = text + "Vacant spike, seeks evil wizard's head\n\n";
    		quests = quests + 1;
    	}
		if (quests<2 && !Campaignstate.victories.contains(Scenario_code.SC_DARK_TEMPLE_2) && Campaignstate.victories.contains(Scenario_code.SC_DARK_TEMPLE_1) && Campaignstate.one_in(2)){
    		text = text + "To all Evil worshippers: Patriarch Xystul will be joining us this week to lead our prayers - don't miss this special service!\n\n";
    		quests = quests + 1;
    	}
		if (quests<2 && !Campaignstate.victories.contains(Scenario_code.SC_LANDSLIDE) && Campaignstate.victories.contains(Scenario_code.SC_CRYPT_2) && Campaignstate.one_in(2)){
    		text = text + "Don't take the Seddon road - a landslide has blocked the path and you will not be able to get over or through...\n\n";
    		quests = quests + 1;
    	}
		if (quests<2 && !Campaignstate.victories.contains(Scenario_code.SC_WATERFALL) && Campaignstate.victories.contains(Scenario_code.SC_CRYPT_2) && Campaignstate.one_in(2)){
    		text = text + "Take a trip to the famous waterfall on the River Cyr! Spectacular views abound! But beware, the pools are not safe for swimming.\n\n";
    		quests = quests + 1;
    	}
    	if (quests<3 && !Campaignstate.victories.contains(Scenario_code.SC_SNAKE_3) && Campaignstate.victories.contains(Scenario_code.SC_RED_DRAGON)){
    		text = text + "A plague of snakes seems ready to overwhelm us! They are everywhere - underfoot, in cupboards, in the stable, in the fields. Where do they come from?\n\n";
    		quests = quests + 1;
    	}
    	if (quests<4 && !Campaignstate.victories.contains(Scenario_code.SC_EVIL_FOREST) && Campaignstate.victories.contains(Scenario_code.SC_RED_DRAGON)){
    		text = text + "The forest to the south-east has become a place of horror. Dark things move beneath the unquiet leaves. For pity's sake go not there.\n\n";
    		quests = quests + 1;
    	}
    	if (quests<5 && !Campaignstate.victories.contains(Scenario_code.SC_RIVERSIDE) && Campaignstate.victories.contains(Scenario_code.SC_RED_DRAGON)){
    		text = text + "An outcast of the Elven race languishes beside the river, in the throes of existential angst. A reward to whoever drives him off, as we are sick of his wittering!\n\n";
    		quests = quests + 1;
    	}
    	if (!Campaignstate.victories.contains(Scenario_code.SC_DESERT) && Campaignstate.victories.contains(Scenario_code.SC_EVIL_FOREST)){
    		text = text + "Brave the blue dragon of the desert sands!\n\n";
    		quests = quests + 1;
    	}
    	if (quests==0){
    		text = text + "Enormous pumpkin seen at village fair!\n\n";
    	}
		notify(this,"scroll","The noticeboard in the town square",text);
    }

    public void onAchievementsButton(View v){
    	String text="";
    	if (Campaignstate.victories.contains(Scenario_code.SC_EASY)){
    		text = text + "You explored the caves near town.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_SWAMP_2)){
    		text = text + "You waded through a horrible swamp.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_TROLL_1)){
    		text = text + "You made it safe for people to cross the bridge.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_CRYPT_1)){
    		text = text + "You disciplined a young necromancer.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_CRYPT_2)){
    		text = text + "You robbed a tomb.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_CRYPT_3)){
    		text = text + "You put the spirit of an ancient warrior to rest.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_TROGLODYTE_1)){
    		text = text + "You eradicated a few troglodytes.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_TROGLODYTE_2)){
    		text = text + "You eradicated a whole bunch of troglodytes.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_EXPLOSIVE_CAVE)){
    		text = text + "You survived an infestation of blast spores.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_ORC_1)){
    		text = text + "You defeated an orcish war band.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_ORC_2)){
    		text = text + "You defeated an orcish encampment.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_ORC_3)){
    		text = text + "You beat a great orc war leader.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_PARTY_1)){
    		text = text + "You defeated the first enemy party.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_PARTY_2)){
    		text = text + "You defeated the second enemy party.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_PARTY_3)){
    		text = text + "You defeated the third enemy party.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_PARTY_4)){
    		text = text + "You defeated the fourth enemy party.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_DOPPELGANGER_PARTY)){
    		text = text + "You confronted yourself.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_LABYRINTH)){
    		text = text + "You defeated the Minotaur of the labyrinth.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_CRAG)){
    		text = text + "You climbed a crag without falling off.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_PYRAMID_1)){
    		text = text + "You did some amateur Egyptology.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_WIZARD_TOWER_1)){
    		text = text + "You saw the color of a wizard's liver.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_WIZARD_TOWER_2)){
    		text = text + "You cut out a wizard's gizzard.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_WIZARD_TOWER_3)){
    		text = text + "You brought home a wizard's head on a spike.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_RED_DRAGON)){
    		text = text + "You defeated the red dragon that was terrorising people.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_DARK_TEMPLE_1)){
    		text = text + "You visited the dark temple, but didn't think much of the service.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_DARK_TEMPLE_2)){
    		text = text + "You desecrated the dark temple and butchered the priests.\n\n";}
		if (Campaignstate.victories.contains(Scenario_code.SC_FOREST_FIRE)){
    		text = text + "You put out a forest fire.\n\n";}
		if (Campaignstate.victories.contains(Scenario_code.SC_LANDSLIDE)){
    		text = text + "You banished an earth elemental to its home plane.\n\n";}
		if (Campaignstate.victories.contains(Scenario_code.SC_WATERFALL)){
    		text = text + "You banished a water elemental to its home plane.\n\n";}
		if (Campaignstate.victories.contains(Scenario_code.SC_SNAKE_1)){
    		text = text + "You killed a few snakes.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_SNAKE_2)){
    		text = text + "You killed a lot of snakes.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_SNAKE_3)){
    		text = text + "You humbled the high priestess of the reptile gods.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_EVIL_FOREST)){
    		text = text + "You defeated the green dragon that was lurking in the forest.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_RIVERSIDE)){
    		text = text + "You brought an end to the dark elf's narcissistic brooding.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_DESERT)){
    		text = text + "You trekked into the desert and defeated the blue dragon.\n\n";}
    	if (Campaignstate.victories.contains(Scenario_code.SC_LICH)){
    		text = text + "You destroyed the undead sorcerer and won the game.\n\n";}
    	if (text.equals("")) text="You are just starting out.\n\n";
    	notify(this,"crown","Your achievements",text);
    }

    static int rez_cost(Charsheet cs){
    	return (int)(Math.max(1,cs.level-3)*0.6*((int)Math.max(1,cs.level-1)*6 + (int)Math.pow(cs.stat1+cs.stat2+cs.stamina+cs.constitution+cs.reflexes+cs.intelligence-15,2)));
    }

    protected void onActivityResult (int requestCode, int resultCode, Intent data){
    	if (requestCode==12 & resultCode==RESULT_OK){
    		boolean won = data.getBooleanExtra("won", false);
    		int gold = data.getIntExtra("gold",0);
    		int n_items = data.getIntExtra("n_items",0);
    		ArrayList<Equipment_type_code> items_found = new ArrayList<Equipment_type_code>();
    		for (int i=0; i<n_items; i++){
    			items_found.add(Equipment_type_code.values()[data.getIntExtra("item_"+i,0)]);
    		}
    		int n_chars = data.getIntExtra("n_chars",0);
    		ArrayList<Boolean> survived = new ArrayList<Boolean>();
    		ArrayList<Integer> xp = new ArrayList<Integer>();
    		int n_survived = 0;
    		int n_died = 0;
    		int penalty = 0;
    		for (int i=0; i<n_chars; i++){
				Charsheet this_character = Campaignstate.chars.get(Campaignstate.current_party.get(i));
    			boolean this_survived = data.getBooleanExtra("survived_"+i,true);
    			if (this_survived){
    				n_survived = n_survived + 1;
	    			int this_xp = data.getIntExtra("xp_"+i,0);
	    			xp.add(this_xp);
    			} else {
    				n_died = n_died + 1;
    				xp.add(0);
    				penalty = penalty + rez_cost(this_character);
    			}
    			survived.add(this_survived);
    			int n_potions_used = data.getIntExtra("n_potions_used_"+i, 0);
    			if (n_potions_used>0){
					for (int j=0; j<n_potions_used; j++){
						Potion_type used = Potion_type.values()[data.getIntExtra("char_"+i+"_potion_"+j, -1)];
						this_character.potions.remove(used);
					}
    			}
    		}
    		if (n_survived>0)
    			Campaignstate.gold = Campaignstate.gold + gold;
			penalty = Math.min(Campaignstate.gold, penalty);
			Campaignstate.gold = Campaignstate.gold - penalty;
    		String title="", text="", image=null;
    		Campaignstate.trips = Campaignstate.trips + 1;
    		Campaignstate.clock_elapsed = Campaignstate.clock_elapsed + data.getDoubleExtra("clock", 0);
    		boolean won_for_first_time = false, finished_game_for_first_time=false;
    		if (n_survived>0){
	    		if (won){
	    			image="crown";
	    			title="You have triumphed!";
	    			text="You return to town.\n\n";
	    			Campaignstate.successes = Campaignstate.successes + 1;
	    			if (!Campaignstate.victories.contains(sc_chosen)) won_for_first_time=true;
	    			if (won_for_first_time && sc_chosen==Scenario_code.SC_LICH){
	    				finished_game_for_first_time=true;}
	    			Campaignstate.victories.add(sc_chosen);
	    		} else if (n_survived>0 & n_died>0){
	    			image="priest_1";
	    			title="You fled!";
	    			text="You straggle back to town, carrying your wounded companions.\n\n";
	    		} else if (n_died==0){
	    			image="loot";
	    			title="You fled!";
	    			text="You return to town.\n\n";
	    		}
	    		if (gold>0)
	    			text=text+"You collected "+gold+" gold.\n\n";
	    		else if (n_items==0)
	    			text=text+"You did not find any treasure.\n\n";
	    		if (penalty>0)
	    			text=text+"You must pay the temple "+penalty+" gold in healing fees.\n\n";
	    		int total_xp = 0;
	    		String level_capped = "";
	    		int n_level_capped = 0;
				int boss_kills = 0;
				if (Campaignstate.victories.contains(Scenario_code.SC_RED_DRAGON)) boss_kills = boss_kills + 1;
				if (Campaignstate.victories.contains(Scenario_code.SC_ORC_3)) boss_kills = boss_kills + 1;
				if (Campaignstate.victories.contains(Scenario_code.SC_RIVERSIDE)) boss_kills = boss_kills + 1;
				if (Campaignstate.victories.contains(Scenario_code.SC_EVIL_FOREST)) boss_kills = boss_kills + 1;
				if (Campaignstate.victories.contains(Scenario_code.SC_SNAKE_3)) boss_kills = boss_kills + 1;
				if (Campaignstate.victories.contains(Scenario_code.SC_DARK_TEMPLE_2)) boss_kills = boss_kills + 1;
				if (Campaignstate.victories.contains(Scenario_code.SC_WIZARD_TOWER_3)) boss_kills = boss_kills + 1;
				if (Campaignstate.victories.contains(Scenario_code.SC_WATERFALL)) boss_kills = boss_kills + 1;
				if (Campaignstate.victories.contains(Scenario_code.SC_LANDSLIDE)) boss_kills = boss_kills + 1;
				if (Campaignstate.victories.contains(Scenario_code.SC_CRYPT_3)) boss_kills = boss_kills + 1;
				if (Campaignstate.victories.contains(Scenario_code.SC_DESERT)) boss_kills = boss_kills + 1;
				if (Campaignstate.victories.contains(Scenario_code.SC_LICH)) boss_kills = boss_kills + 999;
	    		for (int i=0; i<Campaignstate.current_party.size(); i++){
	    			if (survived.get(i) && xp.get(i)>0){
	    				Charsheet this_character = Campaignstate.chars.get(Campaignstate.current_party.get(i));
	    				int earnt = 0;
	    				boolean is_level_capped = false;
	    				if (this_character.level>=5 && boss_kills<1){
	    					is_level_capped = true;
	    				} else if (this_character.level>=6 && boss_kills<2){
	    					is_level_capped = true;
	    				} else if (this_character.level>=7 && boss_kills<4){
	    					is_level_capped = true;
	    				} else if (this_character.level>=8 && boss_kills<6){
	    					is_level_capped = true;
	    				} else if (this_character.level==9 && boss_kills<999){
	    					is_level_capped = true;
	    				} else if (this_character.level==10){
	    					is_level_capped = true;
	    				} else if (this_character.xp+xp.get(i) > Charsheet.xp_needed_for_level(this_character.level+1)){
	    					earnt = Charsheet.xp_needed_for_level(this_character.level+1) - this_character.xp;
	    				} else {
	    					earnt = xp.get(i);
	    				}
	    				if (is_level_capped){
	    					earnt = 0;
	    					if (n_level_capped==0)
	    						level_capped = this_character.name;
	    					else
	    						level_capped = level_capped + ", " + this_character.name;
	    					n_level_capped = n_level_capped + 1;
	    				}
	    				total_xp = total_xp + earnt;
	    				this_character.xp = this_character.xp + earnt;
	    			} else if (!survived.get(i)){
	    				Charsheet this_character = Campaignstate.chars.get(Campaignstate.current_party.get(i));
	    				int lost = Charsheet.percent_progress_lost_on_death_by_level(this_character.level);
	    				this_character.xp = this_character.xp - (int)Math.floor(lost * (this_character.xp-Charsheet.xp_needed_for_level(this_character.level)) / 100.0);
	    			}
	    		}
	    		if (total_xp>0)
	    			text=text+"Your characters earnt "+total_xp+" experience.\n\n";
	    		for (int i=0; i<Campaignstate.current_party.size(); i++){
	    			if (survived.get(i) && xp.get(i)>0){
	    				Charsheet this_character = Campaignstate.chars.get(Campaignstate.current_party.get(i));
	    				if (this_character.xp >= Charsheet.xp_needed_for_level(this_character.level+1)){
	    					this_character.level = this_character.level + 1;
	    					text = text + this_character.name + " reached level " + this_character.level + "!\n\n";
	    				}
	    			}
	    		}
	    		if (n_level_capped>0){
	    			if (n_level_capped==1)
	    				text = text + level_capped + " has reached the level cap and can no longer advance in levels until you have defeated more bosses.\n\n";
	    			else
	    				text = text + level_capped + " have reached the level cap and can no longer advance in levels until you have defeated more bosses.\n\n";
	    		}
	    		if (n_items>0){
	    			text=text+"You found: ";
	    			for (int i=0; i<n_items; i++){
	    				if (n_items>1 && i==n_items-1)
	    					text = text + "and ";
    					Equipment_type_code this_item_code = items_found.get(i);
    					Item it = Campaignstate.i.make_item(this_item_code);
    					text = text + it.name() + ", ";
    					Campaignstate.items_owned.add(Campaignstate.i.make_item(this_item_code));
	    			}
	    			text = text.substring(0, text.length() - 2) + ".\n\n";
	    		}
    		} else {
    			image="skeleton";
    			title="Wiped!";
    			text="Game restored to your last save point.\n\n";
    			text=text+"Penalty of "+penalty+" gold deducted.\n\n";
    		}
    		for (int i=0; i<Campaignstate.current_party.size(); i++){
    			int raw_position = data.getIntExtra("favorite_pos_"+i, -1);
    			if (raw_position>=0){
    				Position_code favorite = Position_code.values()[raw_position];
    				Charsheet this_character = Campaignstate.chars.get(Campaignstate.current_party.get(i));
    				Campaignstate.char_name_to_favorite_position.put(this_character.name, favorite);
    			}
    		}
			Class_code class_code;
			String portrait;
			int level, points, gold_cost, number, random;
    		if (won && won_for_first_time && (sc_chosen==Scenario_code.SC_LANDSLIDE || sc_chosen==Scenario_code.SC_WATERFALL || sc_chosen==Scenario_code.SC_SNAKE_3)){
				text = text + "As a reward, you can upgrade one of your four original characters! An upgrade button will appear at the top of each of their character sheets.\n\n";
				Campaignstate.rebuilds = Campaignstate.rebuilds + 1;
    		}
    		if (won && won_for_first_time && (sc_chosen==Scenario_code.SC_EVIL_FOREST || sc_chosen==Scenario_code.SC_RIVERSIDE || sc_chosen==Scenario_code.SC_FOREST_FIRE || sc_chosen==Scenario_code.SC_DARK_TEMPLE_2 || sc_chosen==Scenario_code.SC_DESERT)){
    			boolean got_recruit = false;
    			for (int i=1; i<200; i++){
    				if (got_recruit) continue;
    				level = Campaignstate.randint(2,5);
    				if (sc_chosen==Scenario_code.SC_DESERT)
    					points = 24;
    				else
    					points = 23;
    				gold_cost = (int)Math.ceil(1.2*(50 * Math.max(level-2,1) * Math.max(level-3,1) * Math.max(0.25,(points-16)/4.0) * Math.max(1+(points-20)/2.0,1)));
    				number = Campaignstate.randint(1,13);
    				random = Campaignstate.randint(1,4);
    				if (random==1){
    					class_code = Class_code.C_WARRIOR;
    					portrait = "warrior_" + number;
    				} else if (random==2){
    					class_code = Class_code.C_MAGE;
    					portrait = "wizard_" + number;
    				} else if (random==3){
    					class_code = Class_code.C_PRIEST;
    					portrait = "priest_" + number;
    				} else {
    					class_code = Class_code.C_ROGUE;
    					portrait = "rogue_" + number;
    				}
    				boolean dupe = false;
    				for (Recruit r : Campaignstate.available_recruits){
    					if (portrait.equals(r.image))
    						dupe = true;
    				}
    				for (Charsheet c : Campaignstate.chars){
    					if (portrait.equals(c.image))
    						dupe = true;
    				}
    				if (!dupe){
    					Campaignstate.available_recruits.add(new Recruit(class_code, portrait, gold_cost, Constants.image_to_default_name.get(portrait), level, points, "", -1, Campaignstate.trips, Campaignstate.clock_elapsed, "Joined you after you completed a heroic mission."));
    					got_recruit = true;
    					text = text + "A hero has decided to join you! You will find them waiting at the inn.\n\n";
    				}
    			}
    		} else {
    			double recruit_chance = 1;
    			if (!won)
    				recruit_chance = recruit_chance*0.5;
    			if (data.getDoubleExtra("clock", 0)<90)
    				recruit_chance = recruit_chance*0.7;
    			if (data.getDoubleExtra("clock", 0)<30)
    				recruit_chance = recruit_chance*0.6;
    			if (Campaignstate.available_recruits.size()>=6) recruit_chance = recruit_chance * 0.05;
    			else if (Campaignstate.available_recruits.size()>=4) recruit_chance = recruit_chance * 0.3;
    			if (Gamestate.w.rand.nextDouble()<recruit_chance){
    				level = Campaignstate.randint(2,4);
    				int party_max_level = 0;
    				for (Charsheet cs : Campaignstate.chars){
    					party_max_level = (int)Math.max(cs.level, party_max_level);
    				}
    				points = 16 + Campaignstate.randint(1,3) + Campaignstate.randint(1,3);
    				gold_cost = (int)Math.ceil(1.2*(50 * Math.max(level-2,1) * Math.max(level-3,1) * Math.max(0.25,(points-16)/4.0) * Math.max(1+(points-20)/2.0,1)));
    				number = Campaignstate.randint(1,13);
    				random = Campaignstate.randint(1,4);
    				boolean min_stat = Campaignstate.one_in(3);
    				if (points>20) min_stat = min_stat || Campaignstate.one_in(3);
    				int min_stat_value = Campaignstate.randint(4, 6);
    				String min_stat_name = "";
    				if (random==1){
    					class_code = Class_code.C_WARRIOR;
    					portrait = "warrior_" + number;
    					if (Campaignstate.one_in(6)) min_stat_name="strength";
    					else if (Campaignstate.one_in(5)) min_stat_name="skill";
    				} else if (random==2){
    					class_code = Class_code.C_MAGE;
    					portrait = "wizard_" + number;
    					if (Campaignstate.one_in(6)) min_stat_name="power";
    					else if (Campaignstate.one_in(5)) min_stat_name="subtlety";
    				} else if (random==3){
    					class_code = Class_code.C_PRIEST;
    					portrait = "priest_" + number;
    					if (Campaignstate.one_in(6)) min_stat_name="valor";
    					else if (Campaignstate.one_in(5)) min_stat_name="wisdom";
    				} else {
    					class_code = Class_code.C_ROGUE;
    					portrait = "rogue_" + number;
    					if (Campaignstate.one_in(6)) min_stat_name="daring";
    					else if (Campaignstate.one_in(5)) min_stat_name="cunning";
    				}
    				if (min_stat && min_stat_name.equals("")){
    					if (Campaignstate.one_in(4)) min_stat_name="constitution";
    					else if (Campaignstate.one_in(3)) min_stat_name="stamina";
    					else if (Campaignstate.one_in(2)) min_stat_name="training";
    					else min_stat_name="reflexes";
    				}
    				boolean dupe = false;
    				for (Recruit r : Campaignstate.available_recruits){
    					if (portrait.equals(r.image))
    						dupe = true;
    				}
    				for (Charsheet c : Campaignstate.chars){
    					if (portrait.equals(c.image))
    						dupe = true;
    				}
    				if (!dupe && level<=party_max_level)
    					Campaignstate.available_recruits.add(new Recruit(class_code, portrait, gold_cost, Constants.image_to_default_name.get(portrait), level, points, min_stat_name, min_stat_value, Campaignstate.trips, Campaignstate.clock_elapsed, "Recruited at the inn."));
    			}
    		}
    		if (Campaignstate.available_recruits.size()>3){
    			for (Recruit r : Campaignstate.available_recruits){
    				if (r.points<23 && r.clock_when_first_available<Campaignstate.clock_elapsed-600 && r.trips_when_first_available<Campaignstate.trips-5 && Campaignstate.one_in(2)){
    					Campaignstate.available_recruits.remove(r);
    					break;
    				}
    			}
    		}
    		if (finished_game_for_first_time) text="Congratulations! You have defeated the undead sorcerer and won the game.";
    		notify(this,image,title,text);
    		tv.setText("Your gold: " + Campaignstate.gold);
    		tv.invalidate();
    		if (Campaignstate.current_party.size()>6){
    			// can happen as a result of Summon Friend
    			Campaignstate.current_party = new ArrayList(Campaignstate.current_party.subList(0, 6));
    		}
    	}
    }

    static ArrayList<Integer> new_party;
    static boolean dialog_loaded;

    public void onChangePartyButton(View v){
    	new_party = new ArrayList<Integer>();
    	for (int i : Campaignstate.current_party){
    		new_party.add(i);}
    	dialog_loaded = false;
        AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this);
        ScrollView sv = new ScrollView(LaunchActivity.this);
        sv.setBackgroundColor(Color.argb(0,0,0,0));
        sv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
        LinearLayout ll = new LinearLayout(LaunchActivity.this);
        ll.setBackgroundColor(Color.argb(0,0,0,0));
        ll.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
        ll.setOrientation(LinearLayout.VERTICAL);
        ll.setGravity(Gravity.TOP);
        for (int i=0; i<Campaignstate.chars.size(); i++){
        	LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,112);
            lp.setMargins(10, 7, 10, 7);
        	ll.addView(new Charsheet_button(LaunchActivity.this,Campaignstate.chars.get(i),i,new_party.contains(i)),lp);
        }
        dialog_loaded = true;
        sv.addView(ll);
        builder.setTitle("Form a party")
        .setCancelable(true)
        .setView(sv)
        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        	public void onClick(DialogInterface dialog, int id) {
        		dialog.cancel();}})
        .setPositiveButton("OK", new MyChangePartyListener(this));
        dlg = builder.create();
        dlg.setOnDismissListener(new OnDismissListener(){
       	public void onDismiss(DialogInterface dialog) {
       		tv.setText("Your gold: " + Campaignstate.gold);
       		tv.invalidate();}
          });
        dlg.show();
    }

    class MyChangePartyListener implements DialogInterface.OnClickListener {
    	Context c;
    	public MyChangePartyListener(Context _c){
    		super();
    		c = _c;
    	}
    	public void onClick(DialogInterface dialog, int id) {
    		dialog.cancel();
    		if (new_party.size()>0){
    			Campaignstate.current_party = new_party;
    		} else {
    			LaunchActivity.notify(c,null,"No characters selected","You must select at least one character to go adventuring");
    		}
		}
    }

    public void onStop(){
    	super.onStop();
    	long ms = (new Date()).getTime();
    	Campaignstate.dump(this,"my_" + ms + ".sav"); // .save
    }

    public BitmapDrawable getDrawableFromAsset(Context context, String strName) {
        InputStream istr;
        Bitmap bitmap = null;
        try {
            istr = assetManager.open(strName);
            bitmap = BitmapFactory.decodeStream(istr);
        } catch (IOException e) {
            finish();
        }
        return new BitmapDrawable(getResources(),bitmap);
    }

    static public int loadSoundFromAsset(String strName){
    	int id;
        try {
        	AssetFileDescriptor descriptor = assetManager.openFd(strName);
        	id = spool.load(descriptor,0);
        	return id;
        } catch (IOException e) {
            return -1;
        }
    }

    static public boolean playSound(String sound_name){
    	if (!Campaignstate.mute){
	    	if (!sound_list.containsKey(sound_name)){
	    		boolean failed = true;
		    	for(String name:soundFileNames){
		    		if (name.equals(sound_name+".wav") || name.equals(sound_name+".mp3")){
		    			sound_list.put(name.substring(0,name.lastIndexOf('.')).toLowerCase(),loadSoundFromAsset("sounds/"+name));
		    			failed = false;
		    			break;
		    		}
		    	}
		    	if (failed){
		    		Log.e("Demo","Missing sound: " + sound_name);
		    		return true;
		    	}
	    	}
	    	int sound_id = ((int)sound_list.get(sound_name));
			if (sound_id>0){
			      float actualVolume = (float) audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
			      float maxVolume = (float) audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
			      float volume = actualVolume / maxVolume;
			      return (LaunchActivity.spool.play(sound_id, volume, volume, 1, 0, 1f)>0);
			}
    	}
		return true;
    }

    static void notify(Context c, String image, String title, String text){
		AlertDialog alertDialog = new AlertDialog.Builder(c).create();
		alertDialog.setTitle(title);
		alertDialog.setMessage(text);
		if (image!=null)
			alertDialog.setIcon(new BitmapDrawable(gi.getImageBasic(image)));
		alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
		   public void onClick(DialogInterface dialog, int which) {
		      dialog.cancel();}
		});
		alertDialog.show();
    }

    class Unchoosable_charsheet_button extends RelativeLayout{
		Charsheet cs;
		int char_number;

		public Unchoosable_charsheet_button (Context context, Charsheet _cs, int _char_number) {
		    super(context);
		    cs = _cs;
		    char_number = _char_number;

		    // TO DO - Want this to look more like a big button
		    setBackgroundColor(Color.WHITE);
		    //
	    	ImageView image_part = new ImageView(context);
	    	image_part.setImageDrawable(new BitmapDrawable(getResources(),gi.getImageBasic(cs.image)));
		    RelativeLayout.LayoutParams left = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		    left.addRule(RelativeLayout.CENTER_VERTICAL);
		    left.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
	        addView(image_part,left);
	        image_part.setId(10000);
	        //
	        TextView name_part = new TextView(context);
	        name_part.setText(cs.name + "  (L" + cs.level + ")");
	        name_part.setTextColor(Color.BLACK);
	        name_part.setTextSize(16);
		    RelativeLayout.LayoutParams next = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		    next.addRule(RelativeLayout.CENTER_VERTICAL);
	        next.addRule(RelativeLayout.RIGHT_OF, image_part.getId());
	        addView(name_part,next);
		    //
	        ImageButton info_part = new ImageButton(context);
	        info_part.setImageBitmap(gi.getImageTiny("question"));
	        info_part.setBackgroundColor(Color.TRANSPARENT);
	        info_part.setOnClickListener(new View.OnClickListener() {
	            public void onClick(View view) {
	            	Intent myIntent = new Intent(LaunchActivity.this, CharsheetDialog.class);
	            	myIntent.putExtra("char_number",char_number);
	    	        LaunchActivity.this.startActivityForResult(myIntent,13);
	            }
			});
			RelativeLayout.LayoutParams last = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
			last.addRule(RelativeLayout.CENTER_VERTICAL);
			last.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
	        addView(info_part,last);
		}
    }

    class Charsheet_button extends RelativeLayout{
		Charsheet cs;
		int char_number;

		public Charsheet_button (Context context, Charsheet _cs, int _char_number, boolean checked) {
		    super(context);
		    cs = _cs;
		    char_number = _char_number;

		    // TO DO - Want this to look more like a big button
		    setBackgroundColor(Color.WHITE);
		    //
	    	ImageView image_part = new ImageView(context);
	    	image_part.setImageDrawable(new BitmapDrawable(getResources(),gi.getImageBasic(cs.image)));
		    RelativeLayout.LayoutParams left = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		    left.addRule(RelativeLayout.CENTER_VERTICAL);
		    left.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
	        addView(image_part,left);
	        image_part.setId(10000);
	        //
	        TextView name_part = new TextView(context);
	        name_part.setText(cs.name + "  (L" + cs.level + ")");
	        name_part.setTextColor(Color.BLACK);
	        name_part.setTextSize(16);
		    RelativeLayout.LayoutParams next = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		    next.addRule(RelativeLayout.CENTER_VERTICAL);
	        next.addRule(RelativeLayout.RIGHT_OF, image_part.getId());
	        addView(name_part,next);
		    //
	    	ToggleButton2 toggle_part = new ToggleButton2(context,this,cs,char_number);
	    	toggle_part.setChecked(checked);
		    RelativeLayout.LayoutParams right = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		    right.addRule(RelativeLayout.CENTER_VERTICAL);
		    right.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
	        addView(toggle_part,right);
	        toggle_part.setId(10001);
	        //
	        ImageButton info_part = new ImageButton(context);
	        info_part.setImageBitmap(gi.getImageTiny("question"));
	        info_part.setBackgroundColor(Color.TRANSPARENT);
	        info_part.setOnClickListener(new View.OnClickListener() {
	            public void onClick(View view) {
	            	Intent myIntent = new Intent(LaunchActivity.this, CharsheetDialog.class);
	            	myIntent.putExtra("char_number",char_number);
	    	        LaunchActivity.this.startActivityForResult(myIntent,13);
	            }
			});
			RelativeLayout.LayoutParams last = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		    last.addRule(RelativeLayout.CENTER_VERTICAL);
		    last.addRule(RelativeLayout.LEFT_OF, toggle_part.getId());
	        addView(info_part,last);
		}
    }

    class Recruit_button extends RelativeLayout{
		Recruit r;

		public Recruit_button (Context context, Recruit _r) {
		    super(context);
		    r = _r;
		    // TO DO - Want this to look more like a big button
		    setBackgroundColor(Color.WHITE);
		    //
	    	ImageView image_part = new ImageView(context);
	    	image_part.setImageDrawable(new BitmapDrawable(getResources(),gi.getImageBasic(r.image)));
		    RelativeLayout.LayoutParams left = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		    left.addRule(RelativeLayout.CENTER_VERTICAL);
		    left.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
	        addView(image_part,left);
	        image_part.setId(30000);
	        //
	        TextView name_part = new TextView(context);
	        name_part.setText(r.name + "  (L" + r.level + " " + Constants.class_code_to_name.get(r.class_code) + ")");
	        name_part.setTextColor(Color.BLACK);
	        name_part.setTextSize(16);
		    RelativeLayout.LayoutParams next = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		    next.addRule(RelativeLayout.ALIGN_PARENT_TOP);
	        next.addRule(RelativeLayout.RIGHT_OF, image_part.getId());
	        addView(name_part,next);
	        name_part.setId(30001);
		    //
	        TextView description_part = new TextView(context);
	        String s=r.points+" points";
	        if (!r.fixed_stat.equals("")){
				if (r.fixed_stat.equals("training"))
					s = s + ", Training ";
				if (r.fixed_stat.equals("stamina"))
					s = s + ", Energy ";
				if (r.fixed_stat.equals("reflexes"))
					s = s + ", Reflexes ";
				if (r.fixed_stat.equals("constitution"))
					s = s + ", Constitution ";
				if (r.fixed_stat.equals("power"))
					s = s + ", Power ";
				if (r.fixed_stat.equals("subtlety"))
					s = s + ", Subtlety ";
				if (r.fixed_stat.equals("strength"))
					s = s + ", Strength ";
				if (r.fixed_stat.equals("skill"))
					s = s + ", Skill ";
				if (r.fixed_stat.equals("valor"))
					s = s + ", Valor ";
				if (r.fixed_stat.equals("wisdom"))
					s = s + ", Wisdom ";
				if (r.fixed_stat.equals("daring"))
					s = s + ", Daring ";
				if (r.fixed_stat.equals("cunning"))
					s = s + ", Cunning ";
				s = s + r.fixed_stat_value;
	        }
	        description_part.setText(s);
	        description_part.setTextColor(Color.BLACK);
	        description_part.setTextSize(12);
		    RelativeLayout.LayoutParams below = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
		    below.addRule(RelativeLayout.RIGHT_OF, image_part.getId());
		    below.addRule(RelativeLayout.BELOW, name_part.getId());
	        addView(description_part,below);
	        description_part.setId(30002);
	        //
	        TextView cost_part = new TextView(context);
	        cost_part.setText("Will join for " + r.current_gold_cost() + " gold");
	        cost_part.setTextColor(Color.BLACK);
	        cost_part.setTextSize(12);
	        RelativeLayout.LayoutParams below2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
	        below2.addRule(RelativeLayout.RIGHT_OF, image_part.getId());
	        below2.addRule(RelativeLayout.BELOW, description_part.getId());
	        addView(cost_part,below2);
		}
    }

	public class ToggleButton2 extends ToggleButton{
		int char_number;
		Charsheet cs;
		Charsheet_button csb;
		Context c;

		public ToggleButton2(Context _c, Charsheet_button _csb, Charsheet _cs, int _char_number){
			super(_c);
			c = _c;
			csb = _csb;
			cs = _cs;
			char_number = _char_number;
			setTextOn("Joined");
			setTextOff("");
			setOnClickListener(new View.OnClickListener() {
	            public void onClick(View view) {
	    			if (LaunchActivity.new_party.contains(char_number)){
	    				LaunchActivity.new_party.remove(LaunchActivity.new_party.indexOf(char_number));
	    			} else if (LaunchActivity.new_party.size()==6){
	    				LaunchActivity.notify(c,null,"Too many characters","Your adventuring party can be no more than six characters...");
	    				playSound("cancel");
	    			} else {
	    				LaunchActivity.new_party.add(char_number);
	    			}
	            }
	        });
		}

		public void setChecked(boolean checked){
			if (LaunchActivity.new_party.size()<6 || checked==false || LaunchActivity.dialog_loaded==false){
				super.setChecked(checked);
			}
		}
	}
}

class WrapInt{
    int value;
    public WrapInt(int _value){
    	value=_value;
    }
}
